<?php
namespace SinoPHP\BbdBoss\Library;

use Monolog\Logger as MonoLogger;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Upfor\UpforPHP\Library\Curl\Curl;

/**
 * Class BasicInformation
 * 获取IP列表,设备信息,物理节点接口
 *
 * @package SinoPHP\BbdBoss\Library
 */
class BasicInformation {

    /**
     * 对外接口 配置文件
     *
     * @var array
     */
    private $requestConfig;

    /**
     * 调用外部API的token
     *
     * @var string
     */
    private $loginToken;
    /**
     * 当前控制器名称
     *
     * @var string
     */
    private $requestController;

    /**
     * 默认的请求开始时间
     *
     * @var integer
     */
    private $defaultStartTime;
    /**
     * 默认的请求结束时间
     *
     * @var integer
     */
    private $defaultEndTime;

    private static $logger = [];

    public function __construct() {
        $this->requestConfig = config(null, 'outApi');
        $this->requestController = substr(__CLASS__, strrpos(__CLASS__, DIRECTORY_SEPARATOR) + 1);
    }

    /**
     * 手动同步数据接口
     *
     * @param string  $type 共三种 ip(ip),device(设备),node(节点)
     * @param integer $startTime
     * @param integer $endTime
     */
    public function manualGetList($type = 'ip', $startTime = 0, $endTime = 0) {
        //校验时间参数
        $this->defaultStartTime = $startTime;
        $this->defaultEndTime = $endTime;
        if (empty($this->defaultStartTime) || (int) $this->defaultStartTime != $this->defaultStartTime) {
            $this->defaultStartTime = time() - 43200;
        }
        if (empty($this->defaultEndTime || (int) $this->defaultEndTime != $this->defaultEndTime)) {
            $this->defaultEndTime = time();
        }
        //根据type 手动更新列表
        switch (strtolower($type)) {
            case 'ip':
                $this->getIPList();
                break;
            case 'node':
                $this->getNodeList();
                break;
            case 'device':
                $this->getDeviceList();
                break;
        }

    }

    /**
     * 同步IP列表
     */
    public function getIpList() {

        $param = $this->buildParam($this->requestConfig['ipList']['apiCode'], $this->requestConfig['ipList']['apiMethod']);

        $data = $this->requestByCurl($param, __FUNCTION__, '同步ip数据错误');
        if (!empty($data['ips'])) {
            $listBuild = [];
            $listMix = [];
            $logBuild = '';
            $logMix = '';
            foreach ($data['ips'] as $key => $value) {
                //自建ip
                if ($value['ip_own_type'] == 0) {
                    $logBuild .= $value['name'] . ' , ';
                    $rowData = [
                        'ip' => $value['name'] ? : '',
                        'hostname' => $value['host_name'] ? : '',
                        'server_area' => $value['data_center'] ? : '',
                        'server_area_id' => $value['data_center_id'] ? : '',
                        'update_time' => time(),
                        'create_time' => time(),
                        'is_delete' => (int) $value['alloc_status'] ? 0 : 1,
                        'sync_ip_id' => $value['ip_id'] ? : '',
                        'isp' => $value['isp'] ? : '',
                        'physical_node' => $value['business_nodes'] ? : '',
                        'physical_node_id' => $value['business_nodes_id'] ? : '',
                        'device_number' => $value['assets_name'] ? : '',
                        'device_number_id' => $value['assets_id'] ? : '',
                        'belong_type' => $value['ip_own_type'],
                        'relate_port' => $value['relate_port'] ? : '',
                        'large_area' => $value['area'] ? : '',
                        'country' => $value['country'] ? : '',
                        'province' => $value['province_name'] ? : '',
                        'city' => $value['city_name'] ? : '',
                        'province_abbreviate' => $value['province_short'] ? : '',
                        'city_abbreviate' => $value['city_short'] ? : '',
                    ];
                    $listBuild[] = $rowData;
                } elseif ($value['ip_own_type'] == 1) {
                    //融合ip
                    $logMix .= $value['name'] . ' , ';
                    $rowDataMix = [
                        'ip' => $value['name'] ? : '',
                        'hostname' => $value['host_name'] ? : '',
                        'server_area' => $value['data_center'] ? : '',
                        'server_area_id' => $value['data_center_id'] ? : '',
                        'update_time' => time(),
                        'create_time' => time(),
                        'is_delete' => (int) $value['alloc_status'] ? 0 : 1,
                        'sync_ip_id' => $value['ip_id'] ? : '',
                        'isp' => $value['isp'] ? : '',
                        'physical_node' => $value['business_nodes'] ? : '',
                        'physical_node_id' => $value['business_nodes_id'] ? : '',
                        'device_number' => $value['assets_name'] ? : '',
                        'device_number_id' => $value['assets_id'] ? : '',
                        'belong_type' => $value['ip_own_type'],
                        'relate_port' => $value['relate_port'] ? : '',
                        'large_area' => $value['area'] ? : '',
                        'country' => $value['country'] ? : '',
                        'province' => $value['province_name'] ? : '',
                        'city' => $value['city_name'] ? : '',
                        'province_abbreviate' => $value['province_short'] ? : '',
                        'city_abbreviate' => $value['city_short'] ? : '',
                    ];
                    $listMix[] = $rowDataMix;
                }
            }
            //var_dump($listBuild,$listMix);die;
            $statusBuild = model('ServerIp')->insert($listBuild, true);
            $statusMix = model('ServerIpMix')->insert($listMix, true);
            //echo $statusMix;
            //die;

            $this->saveLog('syncIp', '自建：' . $statusBuild . '融合：' . $statusMix, ['build' => $logBuild, 'mix' => $logMix]);
            if ($statusBuild === false) {
                die('自建同步失败');
            }
            if ($statusMix === false) {
                die('融合同步失败');
            }
            die('ip同步成功');
        }
        echo '本次同步没有新数据';
    }

    /**
     * 同步物理节点数据
     */
    public function getNodeList() {
        $param = $this->buildParam($this->requestConfig['nodeList']['apiCode'], $this->requestConfig['nodeList']['apiMethod']);
        $data = $this->requestByCurl($param, __FUNCTION__, '同步节点信息错误');

        if ($data['business_nodes']) {
            $list = [];
            $log = '';
            foreach ($data['business_nodes'] as $key => $value) {
                $status = strtoupper($value['status']) == 'ON' ? 0 : 1;
                $log .= $value['node_name'] . ' , ';
                $rowData = [
                    'physical_node_id' => $value['business_id'] ? : '',
                    'physical_node_name' => $value['node_name'] ? : '',
                    'min_limit' => (int) $value['limit_usage'],
                    'max_limit' => (int) $value['high_line'],
                    'node_level' => $value['node_rank'] ? : '',
                    'isp' => $value['isp'] ? : '',
                    'country' => $value['country'] ? : '',
                    'province' => $value['province_name'] ? : '',
                    'city' => $value['city_name'] ? : '',
                    'province_abbreviate' => $value['province_short'] ? : '',
                    'city_abbreviate' => $value['city_short'] ? : '',
                    'server_area' => $value['data_center'] ? : '',
                    'server_area_id' => $value['data_center_id'] ? : '',
                    'large_area' => $value['area'] ? : '',
                    'is_delete' => $status,
                    'update_time' => time(),
                ];
                $list[] = $rowData;
            }

            $status = model('PhysicalNode')->insert($list, true);
            $this->saveLog('syncNode', $status, ['data' => $log]);

            if ($status !== false) {
                die('同步成功');
            }
            die('同步失败');
        }
        echo '本次同步没有新数据';
    }

    /**
     * 同步设备信息数据
     */
    public function getDeviceList() {
        $param = $this->buildParam($this->requestConfig['deviceList']['apiCode'], $this->requestConfig['deviceList']['apiMethod']);

        $data = $this->requestByCurl($param, __FUNCTION__, '同步设备信息错误');

        if ($data['assets']) {
            $list = [];
            $log = '';
            foreach ($data['assets'] as $key => $value) {
                $log .= "$value[asset_desc]" . ' , ';
                $rowData = array(
                    'device_id' => $value['asset_id'] ? : '',
                    'device_number' => $value['asset_number'] ? : '',
                    'device_name' => $value['asset_desc'] ? : '',
                    'hostname' => $value['host_name'] ? : '',
                    'service_type' => $value['aos_product'] ? : '',
                    'model' => $value['model'] ? : '',
                    'location' => $value['location'] ? : '',
                    'cabinet' => $value['asset_id'] ? : '',
                    'manager_switchboard' => $value['manager_switchboard'] ? : '',
                    'business_switchboard' => $value['business_switchboard'] ? : '',
                    'serial_number' => $value['serial_number'] ? : '',
                    'use_department' => $value['used_dept'] ? : '',
                    'throughput' => (int) $value['throughput'],
                    'device_source' => $value['asset_source_type'] ? : '',
                    'server_area' => $value['data_center'] ? : '',
                    'server_area_id' => $value['data_center_id'] ? : '',
                    'status' => (int) $value['up_flag'],
                    'update_time' => time(),
                );
                $list[] = $rowData;
            }
            $status = model('DeviceInfo')->insert($list, true);
            $this->saveLog('syncDevice', $status, ['data' => $log]);

            if ($status !== false) {
                die('同步成功');
            }
            die('同步失败');
        }
        echo '本次同步没有新数据';
    }

    /**
     * 获取客户列表
     *
     */

    public function getCustomer() {
        $url = $this->requestConfig['customerListUrl'];
        //$token = $this->getCustomerToken();
        $token = '18e575325aa8e0d9383bdbeec9b02949';

        $res = $this->requestByCurl($url . 'token=' . $token, __FUNCTION__, '获取客户列表失败');
        if (empty($res['accountResultList'])) {
            return;
        }
        foreach ($res['accountResultList'] as $value) {
            $rowData = [
                'company_name' => $value['acctName'] ? : '',
                'company_alias' => $value['acctAlias'] ? : '',
                'company_address' => $value['acctAlias'] ? : '',
            ];
        }
    }

    /**
     * 获取客户列表登录token
     */
    public function getCustomerToken() {
        $getCustomerToken = cache('getCustomerToken');
        if ($getCustomerToken) {
            return $getCustomerToken;
        }

        $url = $this->requestConfig['customerTokenUrl'];
        $param['username'] = $this->requestConfig['customerUser'];
        $param['password'] = $this->requestConfig['customerPass'];
        $url .= http_build_query($param);
        $res = $this->requestByCurl($url, __FUNCTION__, '获取客户列表token失败');

        cache('getCustomerToken', $res['token'], 200);

        return $res['token'];
    }

    /**
     * 获取平台域名策略决策结果
     */
    public function getPlatDomainPolicyDecision() {
        $action = __FUNCTION__;
        $message = '获取平台域名策略决策结果错误';
        //发起curl get请求
        $curl = new Curl();
        $curl->setTimeout(30);
        $curl->get($this->requestConfig['getPlatDomainPolicyDecisionURL']);
        //curl错误记录日志
        if ($curl->error) {
            $this->mailSend($action, $curl->errorMessage);
            $errorInfo = $curl->errorCode . ' : ' . $curl->errorMessage;
            $this->insertFailLog($action, $errorInfo, $curl->errorMessage);
        }
        $curl->close();
        echo $curl->rawResponse;
        exit();
        $data = @json_decode($curl->rawResponse, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->mailSend($action, json_encode($data));
            $this->insertFailLog($action, $data, '');
        }
        if (!isset($data['code']) || $data['code'] != 0) {
            $this->insertFailLog($action, $data, $message);
        }

        return $data;
    }

    /**
     *构建请求参数
     *
     * @param $apiCode 请求的接口编码
     * @param $method  请求的接口方法
     * @return string
     */
    private function buildParam($apiCode, $method) {
        $jsonData['session'] = $this->getLoginToken();
        $jsonData['interface_code'] = $apiCode;
        if ($this->defaultStartTime || $this->defaultEndTime) {
            $jsonData['start_date'] = date('Y-m-d H:i:s', $this->defaultStartTime);
            $jsonData['end_date'] = date('Y-m-d H:i:s', $this->defaultEndTime);
        } else {
            $jsonData['start_date'] = '2015-04-19 06:54:01';
            $jsonData['end_date'] = '2018-05-20 06:54:01';
            //$jsonData['start_date'] = date('Y-m-d H:i:s',time()-43200);
            //$jsonData['end_date'] = date('Y-m-d H:i:s',time());
        }

        $paramData['method'] = $method;
        $paramData['input_type'] = 'json';
        $paramData['response_type'] = 'json';
        $paramData['rest_data'] = json_encode($jsonData);

        $url = $this->requestConfig['requestURL'] . http_build_query($paramData);

        return $url;
    }

    /**
     * 获取登录token并存入缓存
     *
     * @return bool
     */

    private function getLoginToken() {
        $this->loginToken = cache('baseInformationLoginToken');

        if ($this->loginToken) {
            return $this->loginToken;
        }
        $username = $this->requestConfig['username'];
        $password = $this->requestConfig['password'];

        $paramData['method'] = 'login';
        $paramData['input_type'] = 'json';
        $paramData['response_type'] = 'json';
        $jsonData['user_auth']['user_name'] = $username;
        $jsonData['user_auth']['password'] = $password;
        $paramData['rest_data'] = json_encode($jsonData);

        $param = $this->requestConfig['requestURL'] . http_build_query($paramData);
        $data = $this->requestByCurl($param, __FUNCTION__, '获取token失败');
        cache('baseInformationLoginToken', $data['id'], '3600');

        return $data['id'];
    }

    /**
     * 发起curl请求
     *
     * @param $string $param get请求的参数
     * @param $string $action 调用该方法的方法名
     * @return array
     */
    private function requestByCurl($param, $action, $message = '') {
        //发起curl get请求
        $curl = new Curl();
        $curl->setTimeout(30);
        $curl->get($param);
        //curl错误记录日志
        if ($curl->error) {
            $this->mailSend($action, $curl->errorMessage);
            $errorInfo = $curl->errorCode . ' : ' . $curl->errorMessage;
            $this->insertFailLog($action, $errorInfo, $curl->errorMessage);
        }
        $curl->close();
        $data = @json_decode($curl->rawResponse, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->mailSend($action, json_encode($data));
            $this->insertFailLog($action, $data, '');
        }
        //获取token请求 返回数据处理
        if ($action == 'getLoginToken') {
            if (!isset($data['id'])) {
                $this->insertFailLog($action, $data, $message);
            }

            return $data;
        }
        if ($action == 'getCustomerToken' || $action == 'getCustomer') {
            if ($data['returnCode'] == 1) {
                return $data;
            } else {
                $this->insertFailLog($action, $data, $message);
            }
        }
        if (!isset($data['return_status']) || $data['return_status'] != 0) {
            $this->insertFailLog($action, $data, $message);
        }

        return $data;
    }

    /**
     * curl请求获取数据失败 记录日志
     *
     * @param string $action
     * @param string $data
     * @param string $message
     */
    private function insertFailLog($action, $data, $message) {
        $insertData = [
            'controller' => $this->requestController,
            'action' => $action,
            'create_time' => date('Y-m-d H:i:s', time()),
            'response' => json_encode($data),
        ];
        model('BaseInformationFailLog')->insert($insertData);
        die($message);
    }

    /**
     * @param string $type
     * @param        $status
     * @param array  $context
     */
    private function saveLog($type = 'syncIp', $status, array $context = array()) {

        if (!isset(self::$logger[$type])) {
            $dateFormat = "Y-m-d H:i:s";
            // The default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
            $output = "[%datetime%] %level_name%: %message% %context%\n";
            // Create a formatter
            $formatter = new LineFormatter($output, $dateFormat);

            // Create a handler
            $stream = new StreamHandler(config('log')[$type], MonoLogger::INFO);
            $stream->setFormatter($formatter);

            // Bind it to a logger object
            self::$logger[$type] = new MonoLogger('TaskRunner');
            self::$logger[$type]->pushHandler($stream);

        }

        self::$logger[$type]->log(MonoLogger::INFO, $type . ':' . $status, $context);
    }

    /**
     * curl 报错三次 发送邮件
     *
     * @param string $action   错误来源
     * @param string $errorMsg 错误信息
     */
    private function mailSend($action = '', $errorMsg = '') {
        $basicInformationCurlError = cache('basicInformationCurlError');
        if ($basicInformationCurlError) {
            if ($basicInformationCurlError == 4) {
                sendMail('同步列表' . $action . '失败', 'xuxinjian_xxj@163.com', $errorMsg);
                cache('basicInformationCurlError', 1, 3600);
            } else {
                cache('basicInformationCurlError', $basicInformationCurlError + 1, 3600);
            }
        } else {
            cache('basicInformationCurlError', 1, 3600);
        }
    }

}
